﻿#if NET40 || NET461

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Media;
using System.IO;
using System.Security.Permissions;

namespace Apewer.Internals.Interop
{

    /// <summary>MCI。</summary>
    [HostProtection(SecurityAction.LinkDemand, Resources = HostProtectionResource.ExternalProcessMgmt)]
    [System.Security.SecuritySafeCritical]
    internal sealed class Mci
    {

        private static string MciSend(string argCommand)
        {
            string rs = "";
            WinMM.mciSendString(argCommand, ref rs, 0, IntPtr.Zero);
            return rs;
        }

        /// <summary>播放音频文件。</summary>
        /// <param name="argPath">音频文件的路径。</param>
        public static bool PlayByCommand(string argPath)
        {
            return PlayByCommand(argPath, "audioplay");
        }

        /// <summary>播放音频文件。</summary>
        /// <param name="argPath">音频文件的路径。</param>
        /// <param name="argAlias">别名。</param>
        public static bool PlayByCommand(string argPath, string argAlias = "audioplay")
        {
            if (!string.IsNullOrEmpty(argPath))
            {
                if (File.Exists(argPath))
                {
                    string alias = argAlias;
                    if (string.IsNullOrEmpty(argAlias))
                    {
                        alias = Guid.NewGuid().ToString("n");
                        // valias = Guid.NewGuid().ToString().ToLower().Replace("-", "");
                    }
                    MciSend("open \"" + argPath + "\" alias " + alias + "");
                    MciSend("play " + alias);
                    return true;
                }
            }
            return false;
        }

        /// <summary>播放音频文件。</summary>
        /// <param name="argPath">音频文件的路径。</param>
        public static bool PlayBySnd(string argPath)
        {
            if (File.Exists(argPath))
            {
                WinMM.sndPlaySound(argPath, (long)(Constant.SND_ASYNC));
                return true;
            }
            return false;
        }

        /// <summary>暂停指定别名的音频实例。</summary>
        public static void Pause()
        {
            Pause("audioplay");
        }

        /// <summary>暂停指定别名的音频实例。</summary>
        /// <param name="argAlias">别名。</param>
        public static void Pause(string argAlias)
        {
            MciSend("pause " + argAlias);
        }


        /// <summary>停止指定别名的音频实例。</summary>
        public static void Stop()
        {
            Stop("audioplay");
        }

        /// <summary>停止指定别名的音频实例。</summary>
        /// <param name="argAlias">别名。</param>
        public static void Stop(string argAlias)
        {
            MciSend("stop " + argAlias);
        }

        /// <summary>停止并关闭指定别名的音频实例。</summary>
        public static void Close()
        {
            Close("audioplay");
        }

        /// <summary>停止并关闭指定别名的音频实例。</summary>
        /// <param name="argAlias">别名。</param>
        public static void Close(string argAlias)
        {
            MciSend("stop " + argAlias);
            MciSend("close " + argAlias);
        }

        /// <summary>设置实例的音量。</summary>
        /// <param name="argValue">音量值（0 ~ 1000）。</param>
        public static void Volume(int argValue)
        {
            Volume(argValue, "audioplay");
        }

        /// <summary>设置实例的音量。</summary>
        /// <param name="argAlias">别名。</param>
        /// <param name="argValue">音量值（0 ~ 1000）。</param>
        public static void Volume(int argValue, string argAlias)
        {
            int volume = argValue;
            if (volume < 0) volume = 0;
            if (volume < 1000) volume = 1000;
            MciSend("setaudio " + argAlias + " volume to " + volume.ToString());
        }

        /// <summary>获取实例的长度。</summary>
        public static int Length()
        {
            return Length("audioplay");
        }

        /// <summary>获取实例的长度。</summary>
        /// <param name="argAlias">别名。</param>
        public static int Length(string argAlias)
        {
            string rs = "";
            WinMM.mciSendString("status " + argAlias + " length", ref rs, 64, IntPtr.Zero);
            return Convert.ToInt32(rs);
        }

        /// <summary>获取实例的当前播放进度。</summary>
        public static int Position()
        {
            return Position("audioplay");
        }

        /// <summary>获取实例的当前播放进度。</summary>
        /// <param name="argAlias">别名。</param>
        public static int Position(string argAlias)
        {
            string rs = "";
            WinMM.mciSendString("status " + argAlias + " position", ref rs, 64, IntPtr.Zero);
            return Convert.ToInt32(rs);
        }

        /// <summary>设置播放实例的播放进度。</summary>
        /// <param name="argPosition">目标位置。</param>
        public static void Seek(int argPosition)
        {
            Seek("audioplay", argPosition, false);
        }

        /// <summary>设置播放实例的播放进度。</summary>
        /// <param name="argLast">设置播放进度为末尾，若为 True 则忽略 Position 参数。</param>
        public static void Seek(bool argLast)
        {
            Seek("audioplay", 0, argLast);
        }

        /// <summary>设置播放实例的播放进度。</summary>
        /// <param name="argAlias">别名。</param>
        /// <param name="argPosition">目标位置。</param>
        public static void Seek(string argAlias, int argPosition)
        {
            Seek(argAlias, argPosition, false);
        }

        /// <summary>设置播放实例的播放进度。</summary>
        /// <param name="argAlias">别名。</param>
        /// <param name="argLast">设置播放进度为末尾。</param>
        public static void Seek(string argAlias, bool argLast)
        {
            Seek(argAlias, 0, argLast);
        }

        /// <summary>设置播放实例的播放进度。</summary>
        /// <param name="argAlias">别名。</param>
        /// <param name="argPosition">目标位置。</param>
        /// <param name="argLast">设置播放进度为末尾，若为 True 则忽略 Position 参数。</param>
        public static void Seek(string argAlias, int argPosition, bool argLast)
        {
            if (argLast)
            {
                MciSend("seek " + argAlias + " to end");
            }
            else
            {
                if (argPosition == 0) MciSend("seek " + argAlias + " to start");
                else MciSend("seek " + argAlias + " to " + argPosition.ToString());
            }
            MciSend("play " + argAlias);
        }

        /// <summary>开始录音，若实例已存在则关闭。</summary>
        public static void Record()
        {
            Record("audiorecord", true);
        }

        /// <summary>开始录音，若实例已存在则关闭。</summary>
        /// <param name="argAlias">别名。</param>
        public static void Record(string argAlias)
        {
            Record(argAlias, true);
        }

        /// <summary>开始录音。</summary>
        /// <param name="argAlias">别名。</param>
        /// <param name="argClose">在录音前，若实例已存在则关闭。</param>
        public static void Record(string argAlias, bool argClose)
        {
            if (argClose) Close(argAlias);
            MciSend("set wave bitpersample 16");
            MciSend("set wave samplespersec 44100");
            MciSend("set wave channels 2");
            MciSend("set wave format tag pcm");
            MciSend("open new type waveaudio alias " + argAlias);
            MciSend("record " + argAlias);
        }

        /// <summary>保存录音。</summary>
        /// <param name="argPath">文件路径。</param>
        public static bool Save(string argPath)
        {
            return Save(argPath, "audiorecord");
        }

        /// <summary>保存录音。</summary>
        /// <param name="argPath">文件路径。</param>
        /// <param name="argAlias">别名。</param>
        public static bool Save(string argPath, string argAlias)
        {
            Stop(argAlias);
            if (string.IsNullOrEmpty(argPath)) return false;
            try
            {
                if (File.Exists(argPath)) File.Delete(argPath);
                if (File.Exists(argPath)) return false;
                else MciSend("save " + argAlias + " \"" + argPath + "\"");
                Close(argAlias);
                return File.Exists(argPath);
            }
            catch
            {
                Close(argAlias);
                return false;
            }
        }

    }

}

#endif
